package com.mxy.myapplication.util;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.support.media.ExifInterface;
import android.support.v4.content.FileProvider;
import android.text.Html;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.BitmapEncoder;
import com.google.gson.Gson;
import com.mxy.myapplication.BuildConfig;
import com.mxy.myapplication.R;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;

/**
 * 工具类
 *
 * @author 马晓勇
 */

public abstract class Util {

    /**
     * 判断当前程序运行状态是否是release状态，如果是，则不打印日志
     */
    private static Boolean isdebug = null;

    /**
     * 线程池 使用内部类加载机制创建，使用时再初始化,线程安全
     */
    private static class MyExecutorService {

        private static ExecutorService executorService =
                new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS,
                        new LinkedBlockingQueue<Runnable>());

    }

    /**
     * @return 线程池
     */
    public static ExecutorService getExecutorService() {
        return MyExecutorService.executorService;
    }


    /**
     * Gson 使用内部类加载机制创建，使用时再初始化,线程安全
     */
    private static class GsonInstance {
        private static final Gson GSON = new Gson();
    }

    public static Gson getGsonInstance() {
        return GsonInstance.GSON;
    }


    /**
     * Android 5.0以上沉浸模式
     */
    public static void immerse(Activity cont) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = cont.getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(cont.getResources().getColor(R.color.bantouming));
            window.setNavigationBarColor(cont.getResources().getColor(android.R.color.holo_orange_dark));
        }
    }

    /**
     * Android 5.0真正的沉浸模式，类似《海岛奇兵》，需要安卓5.0以上  onResume时需要重复执行
     */
    public static void realImmerse(Activity cont) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = cont.getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(cont.getResources().getColor(R.color.bantouming));
            window.setNavigationBarColor(cont.getResources().getColor(android.R.color.holo_orange_dark));
        }
    }


    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dipValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue,
                context.getResources().getDisplayMetrics());
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        float density = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / density + 0.5f);
    }

    /**
     * 转换图片成圆形
     *
     * @param bitmap 传入Bitmap对象
     * @return 处理后的图片对象
     */
    public static Bitmap makeRoundBitmap(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int left = 0, top = 0, right = width, bottom = height;
        float roundPx = height / 2;
        if (width > height) {
            left = (width - height) / 2;
            top = 0;
            right = left + height;
            bottom = height;
        } else if (height > width) {
            left = 0;
            top = (height - width) / 2;
            right = width;
            bottom = top + width;
            roundPx = width / 2;
        }
        Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        int color = 0xff424242;
        Paint paint = new Paint();
        Rect rect = new Rect(left, top, right, bottom);
        RectF rectF = new RectF(rect);
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    /**
     * 将原bitmap转换为圆角矩形
     *
     * @param bitmap 图片对象
     * @param pixels 圆角度数  单位像素
     * @return 处理后的圆角bitmap
     */
    public static Bitmap makeRoundCorner(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;
        // 抗锯齿
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }


    /**
     * 手动处理图片分辨率
     * 这个方法推荐使用场景为：
     * 从服务器获取图片
     * 然后处理过后放到控件上
     * 该方法要在异步线程中执行
     * 在主线程中执行，会导致程序卡顿！！！
     *
     * @param f 图片文件对象
     */
    public static void compressPhoto(File f) throws IOException {

        BitmapFactory.Options opt = new BitmapFactory.Options();
        // inJustDecodeBounds如果设置为true，解码器将返回null（没有位图的bitmap对象）
        // 但是调用者仍然可以查询位图的实际像素，系统并没有为位图像素分配内存
        opt.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(f.getPath(), opt);
        // 获取到这个图片的原始宽度和高度
        int picWidth = opt.outWidth;
        int picHeight = opt.outHeight;

        // 期望的图片宽和高
        int requestwidth = 500;
        int requestheight = 500;

        // isSampleSize是表示对图片的缩放程度，比如值为2图片的宽度和高度都变为以前的1/2
        opt.inSampleSize = 1;
        // 根据屏的大小和图片大小计算出缩放比例
        if (picWidth > requestwidth || picHeight > requestheight) {
            if (picWidth > picHeight) {
                opt.inSampleSize = picWidth / requestwidth;
            } else {
                opt.inSampleSize = picHeight / requestheight;
            }
        }
        // 这次再真正地生成一个有像素的，分辨率经过处理的bitmap
        opt.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(f.getPath(), opt);
        // 解决照片旋转角度
        int degree = readPictureDegree(f.getPath());
        Log.i("图片旋转", degree + "");
        bitmap = rotaingImage(degree, bitmap);

        FileOutputStream fos = new FileOutputStream(f);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 降低照片质量，再写入sdcard中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);

        bos.close();
        fos.close();
    }

    /**
     * 读取图片属性：旋转的角度
     *
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    private static int readPictureDegree(String path) throws IOException {
        int degree = 0;

        ExifInterface exifInterface = new ExifInterface(path);
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                degree = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                degree = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                degree = 270;
                break;
            default:
                break;
        }
        return degree;
    }

    /**
     * 旋转图片
     *
     * @param bitmap
     * @return Bitmap
     */
    private static Bitmap rotaingImage(int degree, Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        // 创建新的图片
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,
                true);
    }

    /**
     * 获取当前屏幕实际宽和高（单位px）
     *
     * @param activity
     * @return
     */
    public static DisplayMetrics getDisplay(Activity activity) {
        DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        return metrics;
        //设备独立像素 与 屏幕实际像素
        //1.屏幕密度（dpi=density）不同，决定了屏幕的实际像素也不同,所以用像素设置控件大小，在不同密度的屏幕上，展示效果会出现偏差
        //2.于是谷歌提出了设备独立像素，Density-independent pixel（即dip或dp），1dip=屏幕密度为160的屏幕的1像素
        //3.我们在程序中设置控件的大小，应当使用设备独立像素，程序在运行之后，会自动进行转换，
        //转换公式为:控件在屏幕上显示的实际像素=设备独立像素（程序员手动设置）*（当前屏幕密度/160）;
    }

    /**
     * @param activity
     * @return 屏幕高度(包含状态栏 / 不包括导航栏)
     */
    public static int getScreenHeight(Activity activity) {
        DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        return metrics.heightPixels;
    }

    /**
     * @param activity
     * @return 屏幕宽度
     */
    public static int getScreenWidth(Activity activity) {
        DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        return metrics.widthPixels;
    }

    /**
     * @param context
     * @return 返回当前界面状态栏高度
     */
    public static int getStatusBarHeight(Context context) {
        int statusBarHeight = 0;
        Resources res = context.getResources();
        int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = res.getDimensionPixelSize(resourceId);
        }
        return statusBarHeight;
    }

    /**
     * 设置activity窗体透明度，配合popwindow使用
     *
     * @param activity 窗口activity
     * @param alpha    透明度
     */
    public static void changeWindowAlpha(Activity activity, float alpha) {
        WindowManager.LayoutParams params = activity.getWindow().getAttributes();
        params.alpha = alpha;
        if (alpha == 1) {
            // 不移除该Flag的话,在有视频的页面上的视频会出现黑屏的bug
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        } else {
            // 此行代码主要是解决在华为手机上半透明效果无效的bug
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }
        activity.getWindow().setAttributes(params);
    }


    /**
     * 设置popwindow弹出动画
     *
     * @param activity
     * @param itemClickImageView     需要弹出popwindow而被用户点击的图片
     * @param popupWindow            popwindow
     * @param popwindowView          popwindow视图
     * @param scale                  浮动图标缩放比例
     * @param popdownlayoutHeight_px popwindow底部视图高度  像素
     * @param TranslateX_px          浮动图标位移动画X值
     */
    public static void setPopwindowAnim(final Activity activity, ImageView itemClickImageView,
                                        PopupWindow popupWindow, View popwindowView, float scale,
                                        int popdownlayoutHeight_px, int TranslateX_px) {

        if (activity == null || itemClickImageView == null || popupWindow == null || popwindowView == null) {
            Log.e("错误", "关键参数有null值");
            return;
        }

        // 保存当前打开popwindow整体布局
        ViewGroup popmainlayout = popwindowView.findViewById(R.id.popmainlayout);
        if (popmainlayout == null) {
            showToast(activity, "请为popwindow根布局设置popmainlayout标签");
            return;
        }
        // 设置scrollView中的popmainlayout高度为屏幕高度
        ViewGroup.LayoutParams popmainlayoutLayoutParams = popmainlayout.getLayoutParams();
        popmainlayoutLayoutParams.height = getScreenHeight(activity);

        // 保存当前打开popwindow底部布局
        final View popdownlayout = popwindowView.findViewById(R.id.popdownlayout);
        if (popdownlayout == null) {
            showToast(activity, "请为popwindow底部弹出布局设置popdownlayout标签");
            return;
        }
        if (activity.findViewById(R.id.popwindowanchor) == null) {
            showToast(activity, "请为activit设置popwindow锚点标签popwindowanchor");
            return;
        }
        popdownlayout.setVisibility(View.INVISIBLE);
        // 新建浮动图标
        final ImageView moveimageview = new ImageView(activity);
        moveimageview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showToast(activity, "我是浮动按钮");
            }
        });
        final RelativeLayout.LayoutParams layoutParams =
                new RelativeLayout.LayoutParams(itemClickImageView.getWidth(),
                        itemClickImageView.getHeight());
        int[] movieViewlocationonScreen = new int[2];
        // 获取控件在屏幕中坐标(包含状态栏)
        itemClickImageView.getLocationOnScreen(movieViewlocationonScreen);

        // popwindow的高度总是从状态栏底部开始(即使popwindow高度是match_parent),
        // 又因为getLocationOnScreen是包含状态栏高度的，所以moveimageview的setMargins的高度必须减去状态栏高度
        layoutParams.setMargins(movieViewlocationonScreen[0],
                movieViewlocationonScreen[1] - getStatusBarHeight(activity), 0, 0);
        moveimageview.setScaleType(itemClickImageView.getScaleType());
        moveimageview.setImageDrawable(itemClickImageView.getDrawable());
        popmainlayout.addView(moveimageview, layoutParams);

        // 设置移动图标属性动画
        ObjectAnimator moveviewScaleX = ObjectAnimator.ofFloat(moveimageview, "scaleX", 1f, scale);
        moveviewScaleX.setDuration(300);
        ObjectAnimator moveviewScaleY = ObjectAnimator.ofFloat(moveimageview, "scaleY", 1f, scale);
        moveviewScaleY.setDuration(300);

        // 由于浮动控件需要缩放，所以不能简单按照原控件大小来计算上下左右位移像素，应该考虑到控件进行缩放后移动至目标地点的效果
        ObjectAnimator moveviewTranslateX = ObjectAnimator.ofFloat(moveimageview, "translationX",
                0f, TranslateX_px);
        moveviewTranslateX.setDuration(300);
        ObjectAnimator moveviewTranslateY = ObjectAnimator.ofFloat(moveimageview, "translationY",
                0f,
                Util.getScreenHeight(activity) - movieViewlocationonScreen[1] - popdownlayoutHeight_px);
        moveviewTranslateY.setDuration(300);

        // 设置popdownlayout属性动画
        ObjectAnimator popdownlayoutTranslateY = ObjectAnimator.ofFloat(popdownlayout,
                "translationY", popdownlayoutHeight_px, 0);
        popdownlayoutTranslateY.setDuration(300);
        popdownlayoutTranslateY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                popdownlayout.setVisibility(View.VISIBLE);
            }
        });

        popupWindow.setTouchable(true);
        popupWindow.setOutsideTouchable(false);
        popupWindow.setAnimationStyle(R.style.popwindowdismissstyle);
        View anchor = activity.findViewById(R.id.popwindowanchor);

        // Android 7.0 以上需要做特殊处理 还需要需要根据targetSdkVersion的设置进行测试
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Rect visibleFrame = new Rect();
            anchor.getGlobalVisibleRect(visibleFrame);
            int height =
                    anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom;
            popupWindow.setHeight(height);
            popupWindow.showAsDropDown(anchor);
        } else {
            popupWindow.showAsDropDown(anchor);
        }

        // 启动浮动图片动画
        AnimatorSet animatorSetMoveview = new AnimatorSet();
        animatorSetMoveview.play(moveviewTranslateY).with(moveviewTranslateX).with(moveviewScaleX).with(moveviewScaleY);
        animatorSetMoveview.setStartDelay(300);
        animatorSetMoveview.start();
        // 启动底部布局动画
        AnimatorSet animatorSetPopdownlayout = new AnimatorSet();
        animatorSetPopdownlayout.play(popdownlayoutTranslateY);
        popdownlayoutTranslateY.setStartDelay(300);
        popdownlayoutTranslateY.start();
    }


    /**
     * @param context 判断当前模式是debug还是release
     */
    public static void isDebugMode(Context context) {
        if (isdebug == null) {
            try {
                String packageName = context.getPackageName();
                Class buildConfig = Class.forName(packageName + ".BuildConfig");
                Field DEBUG = buildConfig.getField("DEBUG");
                DEBUG.setAccessible(true);
                isdebug = DEBUG.getBoolean(null);
            } catch (Exception e) {
                isdebug = false;
                e.printStackTrace();
            }
        }
    }

    /**
     * @return 返回当前isdebug值
     */
    private static boolean isdebug() {
        return isdebug == null ? false : isdebug.booleanValue();
    }

    /**
     * 打印debug信息到控制台
     * 一、Log.v 的调试颜色为黑色的，任何消息都会输出，这里的v代表verbose啰嗦的意思，平时使用就是Log.v("","");
     * 二、Log.d的输出颜色是蓝色的，仅输出debug调试的意思，但他会输出上层的信息，过滤起来可以通过DDMS的Logcat标签来选择
     * 三、Log.i的输出为绿色，一般提示性的消息information，它不会输出Log.v和Log.d的信息，但会显示i、w和e的信息
     * 四、Log.w的意思为橙色，可以看作为warning警告，一般需要我们注意优化Android代码，同时选择它后还会输出Log.e的信息。
     * 五、Log.e为红色，可以想到error错误，这里仅显示红色的错误信息，这些错误就需要我们认真的分析，查看栈的信息了。
     **/
    public static void print(String log) {
        if (isdebug()) {
            Log.i("info", log);
        }
    }

    /**
     * 隐藏系统软键盘
     */
    public static void hideInputKeyBroad(Activity cont, View v) {
        InputMethodManager imm =
                (InputMethodManager) cont.getSystemService(Activity.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    /**
     * ImageGetter用于TextView上图文混排
     *
     * @return
     */
    public static Html.ImageGetter getImageGetterInstance(final Activity cont,
                                                          final int textSizePx) {
        Html.ImageGetter imgGetter = new Html.ImageGetter() {
            @Override
            public Drawable getDrawable(String source) {
                int fontH = (int) (dip2px(cont, textSizePx) * 1.5);
                int id = Integer.parseInt(source);
                Drawable d = cont.getResources().getDrawable(id);
                int height = fontH;
                int width =
                        (int) ((float) d.getIntrinsicWidth() / (float) d.getIntrinsicHeight()) * fontH;
                if (width == 0) {
                    width = d.getIntrinsicWidth();
                }
                d.setBounds(0, 0, width, height);
                return d;
            }
        };
        return imgGetter;
    }

    /**
     * 解压目标ZIP文件
     *
     * @param is       目标ZIP文件输入流
     * @param filepath 解压后文件存放目录
     * @throws ZipException 解压文件失败异常
     * @throws IOException  输入输出流异常
     */
    public static void zipFile(InputStream is, String filepath) throws IOException {
        File file = new File(filepath);
        if (!file.exists()) {
            // 创建目标目录
            file.mkdirs();
        }
        ZipInputStream zipInputStream = new ZipInputStream(is);
        // 读取一个进入点
        ZipEntry zipEntry = zipInputStream.getNextEntry();
        byte[] buffer = new byte[1024 * 500];
        // 解压时字节计数
        int count = 0;
        // 如果进入点为空说明已经遍历完所有压缩包中文件和目录
        while (zipEntry != null) {
            if (zipEntry.isDirectory()) {
                file = new File(filepath + File.separator + zipEntry.getName());
                file.mkdirs();
            } else {
                file = new File(filepath + File.separator + zipEntry.getName());
                File parent = file.getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                }
                file.createNewFile();
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                while ((count = zipInputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, count);
                }
                fileOutputStream.close();
            }
            zipEntry = zipInputStream.getNextEntry();
        }
        zipInputStream.close();
        is.close();
    }

    private volatile static Toast toast;

    private static Toast getToast(Context context) {
        if (toast == null) {
            synchronized (Toast.class) {
                if (toast == null) {
                    //不能用new的方式
                    toast = Toast.makeText(context, "", Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    return toast;
                } else {
                    return toast;
                }
            }
        } else {
            return toast;
        }
    }

    public static void showToast(Context context, String content) {
        if (context != null) {
            if (getToast(context) != null) {
                getToast(context).setText(content);
                getToast(context).show();
            }
        }
    }


    /**
     * 使用google官方推荐的Glide框架加载图片
     * <p>
     * 注意事项:
     * <p>
     * 图片控件最好设置固定宽高，提高加载效率和缓存效率
     * 默认缓存路径为DATA目录下APP的私有文件夹，开发者无特殊要求不需要改写
     * 图片控件一定不能使用setTag(Object o)方法，因为Glide本身会调用该方法，如果开发者自己使用了该方法，100%出现异常
     * 可以使用setTag(int key,Object o)方法作为替代，使用getTag(int key)获取tag   该方法的key值必须在values文件夹中strings
     * .xml文件进行id定义，不能手写
     *
     * @param context                    上下文 注:一定要传入activity对象本身，不能传入applicationContext，因为Glide
     *                                   的生命周期会自动绑定Context对象，如果传入applicationContext，那么当Activity
     *                                   销毁之后，Glide的访问线程依然存在，造成内存溢出。
     *                                   Fragment传入getActivity()即可
     * @param imageurl                   可以传入:图片网络URL，资源文件drawableid,SD卡图片文件URI,File 文件对象
     * @param placeHolderPhotoDrawableId 占位图drawableid
     * @param errorPhotoDrawableId       加载失败drawableid
     * @param imageView                  图片控件
     */
    public static void showImageWithGlide(Context context, Integer imageurl,
                                          int placeHolderPhotoDrawableId,
                                          int errorPhotoDrawableId, ImageView imageView) {

        String tag = (String) imageView.getTag(R.string.glideTagKey);

        BitmapRequestBuilder bitmapRequestBuilder = Glide.with(context)
                .load(imageurl)
                .asBitmap()
                //PNG图片是没有“质量”一说的
                .encoder(new BitmapEncoder(Bitmap.CompressFormat.PNG, 100))
                .placeholder(placeHolderPhotoDrawableId)
                .error(errorPhotoDrawableId)
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .dontAnimate()//防止placeholder与网络加载图片比例不一致造成的图片被强行拉伸的错误
                .animate(R.anim.alpha);


        //圆形圆角图片
        if ("圆形".equals(tag)) {
            bitmapRequestBuilder.transform(new GlideCircleTransform(context));
        } else if ("圆角".equals(tag)) {
            bitmapRequestBuilder.transform(new GlideRoundCornerTransform(context));
        }

        //开始加载图片
        bitmapRequestBuilder.into(imageView);
    }

    /**
     * @return 获取一个32位的UUID字符串，新增客户门头和联系人照片时文件名使用
     */
    public static String getUUid() {
        return UUID.randomUUID().toString().replace("-", "");
    }


    /**
     * 调起电话拨号界面
     */
    public static void makeCall(Context context, String phonenumber) {
        context.startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phonenumber)));
    }

    /**
     * @param email 发送邮件接收人地址
     */
    public static void startSendEmailIntent(Context context, String email) {
        //必须要加 "mailto:"
        Uri uri = Uri.parse("mailto:" + email);
        Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
        // 抄送人
        intent.putExtra(Intent.EXTRA_CC, email);
        // 主题
        intent.putExtra(Intent.EXTRA_SUBJECT, "");
        // 正文
        intent.putExtra(Intent.EXTRA_TEXT, "");
        context.startActivity(Intent.createChooser(intent, "请选择邮件应用"));
    }


    /**
     * @param activity
     * @param turnOnOrOff true开启高亮+禁止屏幕休眠    false相反
     */
    public static void screenHighLight(Activity activity, boolean turnOnOrOff) {

        //屏幕高亮
        if (turnOnOrOff) {
            WindowManager.LayoutParams windowLayoutParams = activity.getWindow().getAttributes();
            windowLayoutParams.screenBrightness =
                    WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL;
            activity.getWindow().setAttributes(windowLayoutParams);
            //关闭禁止休眠
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            //关闭高亮
            WindowManager.LayoutParams windowLayoutParams = activity.getWindow().getAttributes();
            windowLayoutParams.screenBrightness =
                    WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
            activity.getWindow().setAttributes(windowLayoutParams);
            //关闭禁止休眠
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    }

    /**
     * 判断service是否存活
     *
     * @param context
     * @param className
     * @return
     */
    public static boolean isServiceExisted(Context context, String className) {
        ActivityManager activityManager =
                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if (activityManager != null) {
            List<ActivityManager.RunningServiceInfo> serviceList =
                    activityManager.getRunningServices(Integer.MAX_VALUE);
            if (serviceList.size() > 0) {
                for (int i = 0; i < serviceList.size(); i++) {
                    ActivityManager.RunningServiceInfo serviceInfo = serviceList.get(i);
                    ComponentName serviceName = serviceInfo.service;
                    if (serviceName.getClassName().equals(className)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    /**
     * @param context
     * @param pid     进程id
     * @return 进程名
     */
    public static String getProcessName(Context context, int pid) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        if (am != null) {
            List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
            if (runningApps == null) {
                return "123";
            }
            for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
                if (procInfo.pid == pid) {
                    return procInfo.processName;
                }
            }
        }

        return "123";
    }


    /**
     * @param application
     * @return 获取manifests中定义的metaData值 例如接口地址，例如渠道号等
     */
    public static String getAppMetaData(Application application, String metaKey) {
        try {
            PackageManager pm = application.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(application.getPackageName(),
                    PackageManager.GET_META_DATA);
            return appInfo.metaData.getString(metaKey);
        } catch (PackageManager.NameNotFoundException ignored) {
            return "";
        }
    }

    /**
     * 隐式意图启动Activity
     *
     * @param activity
     * @param intent
     */
    public static void startActivityByAction(Activity activity, Intent intent) {
        if (activity != null && intent != null) {
            try {
                activity.startActivity(intent);
            } catch (Exception e) {
                showToast(activity, "组件未装载");
                e.printStackTrace();
            }
        }
    }

    /**
     * 在手机上安装apk
     *
     * @param context
     * @param apkFile apk文件
     */
    public static void openAPK(Context context, File apkFile) {

        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(android.content.Intent.ACTION_VIEW);
        // 设置目标文件的打开方式
        String type = "application/vnd.android.package-archive";
        //安卓7.0及以上
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // 将文件转换成content://Uri的形式     BuildConfig.APPLICATION_ID直接是应用的包名
            Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID +
                    ".provider", apkFile);
            // 申请临时访问权限
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            intent.setDataAndType(apkUri, type);
        } else {
            // 设置intent的目标文件的uri与打开方式MimeType
            intent.setDataAndType(Uri.fromFile(apkFile), type);
        }
        context.startActivity(intent);
    }


    /**
     * Drawable转Bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {

        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ?
                Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);
        //注意，下面三行代码要用到，否则在View或者SurfaceView里的canvas.drawBitmap会看不到图
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);

        return bitmap;
    }

    /**
     * 一些算法
     */
    public static void arithmetic() {
        //冒泡排序
        int[] numArray = new int[]{9, 8, 7, 6, 4, 5, 3, 2, 1, 0};
        boolean looper = false;
        int counts = 0;
        for (int i = 0; i < numArray.length - 1; i++) {
            for (int j = 0; j < numArray.length - 1; j++) {
                if (numArray[j] < numArray[j + 1]) {
                    int temp = numArray[j];
                    numArray[j] = numArray[j + 1];
                    numArray[j + 1] = temp;
                    looper = true;
                }
            }
            counts++;
            if (!looper) {
                break;
            } else {
                looper = false;
            }
        }
        System.out.println("循环次数 : " + counts);
        for (int num : numArray) {
            System.out.print(num + ",");
        }

        //输出99乘法表
        for (int i = 1; i <= 9; i++) {
            System.out.println();
            for (int j = 1; j <= i; j++) {
                System.out.print(j + "*" + i + "=" + String.valueOf(i * j) + " ");
            }
        }

        //字符串反序
        String a = "jkfh_fgh*879";
        char[] charArray = a.toCharArray();
        StringBuilder stringBuilder1 = new StringBuilder();
        for (int i = charArray.length - 1; i >= 0; i--) {
            stringBuilder1.append(charArray[i]);
        }
        System.out.println(stringBuilder1.toString());

        //字符串去重复
        String aa = "ffghabcabcabcabcacbabcfgh";
        charArray = aa.toCharArray();

        for (int i = 0; i < aa.length(); i++) {
            for (int j = i + 1; j < aa.length(); j++) {
                if (charArray[i] == charArray[j] && charArray[i] != ' ') {
                    charArray[j] = ' ';
                }
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (char c : charArray) {
            if (c != ' ') {
                stringBuilder.append(c);
            }
        }
        System.out.println("去重后的字符串 : " + stringBuilder.toString());
    }
}